﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace BaiduMapTileCutter.GaoDe
{
    public partial class GaoDeForm : Form
    {
        private ZoomInfo zoomInfo = new ZoomInfo();

        Thread doProcess = null;
        string imagePath;
        /// <summary>
        /// 宽度
        /// </summary>
        int iWidth;
        /// <summary>
        /// 高度
        /// </summary>
        int iHeight;
        /// <summary>
        /// 当前缩放级别
        /// </summary>
        int level;


        /// <summary>
        /// 文件路径
        /// </summary>
        string path;

        string fname;
        string outputPath;
        /// <summary>
        /// 起始点坐标
        /// </summary>
        BMap.Point pointStart;

        double maxExtentLeft = -2.00375e+007;
        double maxExtentTop = 2.00375e+007;

        private static int processVal = 0;
        /// <summary>
        /// 地图精度(分辨率)
        /// </summary>
        double[] resolution =
            new double[]
            {
                    156543.033928,          //0+1
                    78271.5169639999,       //1+1
                    39135.7584820001,       //2+1
                    19567.8792409999,       //3+1
                    9783.93962049996,       //4+1
                    2445.98490512499,       //5+1
                    1222.99245256249,       //6+1
                    611.49622628138,        //7+1
                    305.748113140558,       //8+1
                    152.874056570411,       //9+1
                    76.4370282850732,       //10+1
                    38.2185141425366,       //11+1
                    19.1092570712683,       //12+1
                    9.55462853563415,       //13+1
                    4.77731426794937,       //14+1
                    2.388657133483887f,//  2.388657133483887     //15+1
                    1.1943285667419434f,     //16+1
                    0.5971642833709717f,     //17+1
                    0.298582141647617f       //18+1
            };

        public GaoDeForm()
        {
            InitializeComponent();
        }

        private void Button1_Click(object sender, EventArgs e)
        {

            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                txbImage.Text = openFileDialog1.FileName;

                pbxImageToCut.Image = new System.Drawing.Bitmap(txbImage.Text);

            }

        }

        /// <summary>
        /// 执行切图操作
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="zoom"></param>
        private void CutImages(string fileName, int zoom)
        {

            double lat = Convert.ToDouble(txtLat.Text);
            double lon = Convert.ToDouble(txtLon.Text);

            //取得顶点
            BMap.Point point = ConvertPoint(lat, lon, zoom);

            int iLeft = 0, iTop = 0;
            // 加载图片
            System.Drawing.Image image = new System.Drawing.Bitmap(fileName);


            for (int i = 0; i < image.Height / iWidth + 1; i++)
            {
                iTop = i * iWidth;
                for (int j = 0; j < image.Width / iHeight + 1; j++)
                {
                    iLeft = j * iHeight;

                    // 目标区域
                    Rectangle destRect = new Rectangle(0, 0, iWidth, iHeight);
                    // 源图区域
                    Rectangle srcRect = new Rectangle(iLeft, iTop, iWidth, iHeight);

                    // 新建Graphics对象
                    Bitmap newImage = new Bitmap(iWidth, iHeight);
                    Graphics g = Graphics.FromImage(newImage);

                    // 绘图平滑程序
                    g.SmoothingMode = SmoothingMode.HighQuality;

                    // 图片输出质量
                    g.CompositingQuality = CompositingQuality.HighQuality;

                    // 输出到newImage对象
                    g.DrawImage(image, destRect, srcRect, GraphicsUnit.Pixel);

                    // 释放绘图对象
                    g.Dispose();

                    //如果文件不存在
                    if (!Directory.Exists(txtOutPut.Text + "\\" + zoom))
                    {
                        Directory.CreateDirectory(txtOutPut.Text + "\\" + zoom);
                    }
                    string strDestFile = string.Format(txtOutPut.Text + @"\" + zoom + @"\" + @fname + ".png", (point.X + j),
                        (point.Y + i));

                    newImage.Save(strDestFile, ImageFormat.Png);

                    float finished = (i * (image.Height / iWidth + 1) + j + 1) * 10000;
                    float total = ((image.Height / iWidth) * (image.Width / iHeight)) * 100;
                    float result = finished / total;

                    Thread.Sleep(100);
                }

            }
            image.Dispose();
        }

        /// <summary>
        /// （内部换算，核心）将经纬度按照缩放值转换成坐标点
        /// </summary>
        /// <param name="lat"></param>
        /// <param name="lng"></param>
        /// <param name="zoom"></param>
        /// <returns></returns>
        public BMap.Point ConvertPoint(double lat, double lng, int zoom)
        {

            //        var loc1:*=0.00449797741722;
            //var loc2:*=0.00213;
            //16级为基准，17级的lat不变
            //与16级相比,17级与16级相比，lng需要调整，lat不需要调整
            if (zoom == 17)
            {
                lng += 0.00274;
            }
            if (zoom == 18)
            {
                lng += 0.00274;
                //lng = lng;// +0.00136;//120.???
                lat = lat + 0.00117;//31.??
            }




            BMap.Point p = LngLatToMercator(lng, lat); ;// new BMap.GoogleMapsProjection().fromLatLngToPoint(lat, lng, zoom);// LngLatToMercator(lng, lat);

            //BMap.Point p2 = LngLatToMercator(lng, lat);
            //BMap.Point p3 = new BMap.GoogleMapsProjection().MCT84Bl2xy(lng, lat);

            //地图的分辨率
            double res = resolution[zoom - 1];

            double originTileX = Math.Round((p.X - this.maxExtentLeft) / (res * Convert.ToDouble(txbWidth.Text)));
            double originTileY = Math.Round((this.maxExtentTop - p.Y) / (res * Convert.ToDouble(txbHeight.Text)));

            double zoomPower = Math.Pow(2, zoom);

            if (originTileY < 0 || originTileY >= zoomPower || originTileX < 0 || originTileX >= zoomPower)
            {
                return null;
            }

            originTileX = (originTileX % zoomPower + zoomPower) % zoomPower;
            originTileY = (originTileY % zoomPower + zoomPower) % zoomPower;

            return new BMap.Point(originTileX, originTileY);


        }


        //像素X到经度  
        public static double pixelToLng(double pixelX, int zoom)
        {
            return pixelX * 360 / (256 * 2 ^ zoom) - 180;
        }


        //经度到像素
        public double lngToPixel(double lng, int zoom)
        {
            return (lng + 180) * (256L << zoom) / 360;
        }

        //纬度到像素Y
        public double latToPixel(double lat, int zoom)
        {
            double siny = Math.Sin(lat * Math.PI / 180);
            double y = Math.Log((1 + siny) / (1 - siny));
            return (128 << zoom) * (1 - y / (2 * Math.PI));
        }

       

        /// <summary>
        /// 经纬度转换成坐标值
        /// </summary>
        /// <param name="lon"></param>
        /// <param name="lat"></param>
        /// <returns></returns>
        public BMap.Point LngLatToMercator(double lon, double lat)
        {

            //            var loc1:*=0.00449797741722;
            //var loc2:*=0.00213;
            lon = lon + 0.00449797741722;
            lat = lat - 0.00213;
            double x = lon * 20037508.34 / 180;
            double y = -180;
            if (lat > -90)
                y = Math.Log(Math.Tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);

            y = y * 20037508.34 / 180;

            //double x = latToPixel(lat,zoom);
            //double y = lngToPixel(lon,zoom);

            return new BMap.Point(x, y);

        }

        private void button3_Click(object sender, EventArgs e)
        {
            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
            {
                txtOutPut.Text = folderBrowserDialog1.SelectedPath;
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            this.progressBar1.Value = processVal;
            if (processVal >= this.progressBar1.Value) {
                this.timer1.Stop();
                this.timer1.Enabled = false;                
            }
         
        }

        private void button4_Click(object sender, EventArgs e)
        {
            if (doProcess != null)
            {
                try
                {
                    doProcess.Abort();
                }
                catch
                {
                }
            }
        }

        private void txbWidth_TextChanged(object sender, EventArgs e)
        {
            this.txbHeight.Text = ((TextBox)sender).Text;
        }

        private void Button2_Click_1(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;
            try
            {
                this.outputPath = txtOutPut.Text;

                imagePath = txbImage.Text.Trim();

                iWidth = Convert.ToInt32(txbWidth.Text);
                iHeight = Convert.ToInt32(txbHeight.Text);


                //文件名
                fname = txbFname.Text.Trim();
                if (fname == String.Empty)
                {
                    fname = @"{0},{1}";
                }

                path = txtOutPut.Text;
                if (path == "" || imagePath == "")
                {
                    MessageBox.Show("请选择图片及输出路径");
                    return;
                }

                CalcZoomInfo();

                // 加载图片
                System.Drawing.Image image = new System.Drawing.Bitmap(imagePath);



                progressBar1.Maximum = zoomInfo.MaxZoom - zoomInfo.MinZoom;
                this.timer1.Enabled = true;
                this.timer1.Start();
                processVal = 0;
                for (int i = zoomInfo.MinZoom; i <= zoomInfo.MaxZoom; i++)
                {

                    processVal += 1;
                    Size newSize = new Size();
                    double num2 = Math.Pow(2.0, (double)(zoomInfo.ImageZoom - i));

                    newSize.Height = (int)(((double)image.Height) / num2);
                    newSize.Width = (int)(((double)image.Width) / num2);

                    if ((newSize.Width != 0) && (newSize.Height != 0))
                    {
                        Bitmap bitmap2 = new Bitmap(image, newSize);
                        string filename = this.outputPath + "/temp" + i + ".png";
                        bitmap2.Save(filename);

                        this.CutImages(filename, i);
                        bitmap2.Dispose();
                        try
                        {
                            File.Delete(this.outputPath + "/temp" + i + ".png");
                        }
                        catch { }
                    }

                }
                MessageBox.Show("OK!");
            }
            finally {
                this.Cursor = Cursors.Default;
            }
        }

        private void Button3_Click_1(object sender, EventArgs e)
        {
            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
            {
                txtOutPut.Text = folderBrowserDialog1.SelectedPath;
            }
        }


        private void rdbCustom_CheckedChanged(object sender, EventArgs e)
        {
            updateUI();
        }

        private void rdbAuto_CheckedChanged(object sender, EventArgs e)
        {
            updateUI();
        }

        private void updateUI()
        {
            bool zoomTbxEnable = true;
            if (rdbAuto.Checked == true)
            {
                zoomTbxEnable = false;
            }
            else if (rdbCustom.Checked == true)
            {
                zoomTbxEnable = true;
            }
            cbxImageOriginZoom.Enabled = zoomTbxEnable;
            cbxMaxZoom.Enabled = zoomTbxEnable;
            cbxMinZoom.Enabled = zoomTbxEnable;
        }

        public void CalcZoomInfo()
        {
            if (rdbAuto.Checked == true)
            {
                CalcImageZoom();
            }
            else
            {
                zoomInfo.MinZoom = Int32.Parse((string)cbxMinZoom.SelectedItem);
                zoomInfo.MaxZoom = Int32.Parse((string)cbxMaxZoom.SelectedItem);
                if (cbxImageOriginZoom.SelectedItem == null)
                {
                    MessageBox.Show("请选择默认放大级别");
                    return;
                }
                zoomInfo.ImageZoom = Int32.Parse((string)cbxImageOriginZoom.SelectedItem);
            }
        }

        /// <summary>
        /// 根据图片宽度和高度自动计算适合的级别
        /// </summary>
        private void CalcImageZoom()
        {   
            Bitmap bitmap = new Bitmap(txbImage.Text.Trim());
            int imgHeight = bitmap.Height;
            int imgWidth = bitmap.Width;
            Console.WriteLine(imgHeight + ", " + imgWidth);
            int imgZoom = 3;
            while (imgHeight > 256 && imgWidth > 256)
            {
                imgHeight /= 2;
                imgWidth /= 2;
                imgZoom++;
            }
            zoomInfo.ImageZoom = imgZoom;
            zoomInfo.MaxZoom = imgZoom;
            zoomInfo.MinZoom = 3;
            Console.WriteLine(zoomInfo.MinZoom + ", " + zoomInfo.MaxZoom + ", " + zoomInfo.ImageZoom);
        }

        private void Button4_Click_1(object sender, EventArgs e)
        {
            if (doProcess != null)
            {
                try
                {
                    doProcess.Abort();
                }
                catch
                {
                }
            }
        }
    }
}
